#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <pwd.h>
#include <sys/param.h>
#include <grp.h>

#include "tiempo.h"
// Cabeceiras:
char *obterTipo(mode_t m);
char *obterPermisos(mode_t m);
void imprimeInfo(struct stat st); 
int estaModificado(time_t t, int dias, int seg);
int examinarArquivo(char *path, char *arquivo, int dias, int seg);
int procesarDirectorio(char *dir, int dias, int seg);



char *obterTipo(mode_t m) {
	static char tipo[15];
	strcpy(tipo, "");

	if (S_ISBLK(m))
		strcpy(tipo, "block special");
	else if (S_ISCHR(m))
		strcpy(tipo, "char special");
	else if (S_ISDIR(m))
		strcpy(tipo, "directory");
	else if (S_ISFIFO(m))
		strcpy(tipo, "fifo or socket");
	else if (S_ISREG(m))
		strcpy(tipo, "regular file");
	else if (S_ISLNK(m))
		strcpy(tipo, "symbolic link");
	else if (S_ISSOCK(m))
		strcpy(tipo, "socket");
	else
		strcpy(tipo, "unknouwn type");
	
	return (tipo);
}

char *obterPermisos(mode_t m) {
	static char permisos[10];
	strcpy(permisos, "");
	//Permisos usuario
	if ( m & S_IRUSR ) strcat(permisos,"r"); else strcat(permisos,"-");
	if ( m & S_IWUSR ) strcat(permisos,"w"); else strcat(permisos,"-");
	if ( m & S_IXUSR ) strcat(permisos,"x"); else strcat(permisos,"-");
	//Permisos grupo
	if ( m & S_IRGRP ) strcat(permisos,"r"); else strcat(permisos,"-");
	if ( m & S_IWGRP ) strcat(permisos,"w"); else strcat(permisos,"-");
	if ( m & S_IXGRP ) strcat(permisos,"x"); else strcat(permisos,"-");
	//Permisos outros
	if ( m & S_IROTH ) strcat(permisos,"r"); else strcat(permisos,"-");
	if ( m & S_IWOTH ) strcat(permisos,"w"); else strcat(permisos,"-");
	if ( m & S_IXOTH ) strcat(permisos,"x"); else strcat(permisos,"-");
	
	return permisos;
}

void imprimeInfo(struct stat st) {
  char dono[200], grupo[200];

  if (getpwuid(st.st_uid) == NULL)
	sprintf(dono,"");
  else 
	sprintf(dono,"%s",(getpwuid(st.st_uid))->pw_name); 
  if (getgrgid(st.st_gid) == NULL)
	sprintf(grupo,"");
  else 
	sprintf(grupo,"%s",(getgrgid(st.st_gid))->gr_name); 
  
  printf("\tDono: %s\n", dono);
  printf("\tGrupo: %s\n", grupo);	
  printf("\tInodo: %d\n", st.st_ino);
  printf("\tTamanho: %d bytes\n", (int)st.st_size);
  printf("\tNumero de bloques: %d\n", (int)st.st_blocks);
  printf("\tPermisos: %s\n", obterPermisos(st.st_mode));
  printf("\tNumero de enlaces: %d\n", (int)st.st_nlink);
}

// Cando dias >= 0 comparamo-lo t_modificacion co de getStartTimeDaysBefore
// Noutro caso comparamo-lo coa ultima revision: actual - t_revision 
int estaModificado(time_t t, int dias, int seg) {
	if (dias < 0 && seg > 0) return ( t > (getCurrentTime() - seg) );
	else return ( t > getStartTimeDaysBefore(dias) );
}

int examinarArquivo(char *path, char *arquivo, int dias, int seg) {
	char ruta[512];
	sprintf(ruta, "%s/%s", path, arquivo);

	struct stat st;

	if (lstat(ruta, &st) == -1) {
		perror("Erro facendo stat sobre o arquivo");
		return -1;
	}

	if (!estaModificado(st.st_mtime, dias, seg)) return 0;
	
	//Se e un directorio (distinto de "." e ".." exploramos recursivamente
	if(S_ISDIR(st.st_mode)) {
		if(!strcmp(arquivo, ".") || !strcmp(arquivo, "..")) return 0;
		procesarDirectorio(ruta, dias, seg);
		//	return 0; //Porque o directorio actual non o quero mostrar
	}
	
	
	printf("Encontrado arquivo:    %s    modificado:    %s\n", ruta, getTimeAsString(st.st_mtime));

	
	printf("\tTipo: %s", obterTipo(st.st_mode));
	
	char rpath[512];
	
	if(S_ISLNK(st.st_mode)) {
		realpath(ruta,rpath);
		printf(" -> %s\n", rpath);
	}
	else puts("");
	
	imprimeInfo(st);

	return 0;
}


// Un valor de days < 0 significa que se trata da 2 e posteriores iteracions
// Un valor de days >= 0 significa que se trata da 1 iteracion.
int procesarDirectorio(char *dir, int dias, int seg) {
	DIR *d = opendir(dir);
		if (d == NULL) {
		  // fprintf(stderr,"\n erro ao abrir directorio %s ", dir);
		  //perror("Erro abrindo o directorio ");
		return -1;
		}

	struct dirent *dp;
	while ((dp=readdir(d)) != NULL) {
		if (examinarArquivo(dir, dp->d_name, dias, seg) == -1)
			return -1;
	}
	if (closedir(d) == -1) {
		perror("Erro cerrando o directorio");
		return -1;
	}
	return  0;
}


